package com.xiaoa.aop;

import java.io.File;


import java.lang.reflect.Method;
import java.util.LinkedHashMap;

import org.apache.commons.io.FileUtils;
import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.alibaba.fastjson.JSON;
import com.xiaoa.annotation.JsonCache;
import com.xiaoa.base.Response;
import com.xiaoa.utils.ExceptionUtils;

/**
 * spring 切入点
 */
@Component
@Aspect
public class TangentAspect {
	
	 //设置切点：使用xml，在xml中配置
//    @Pointcut("execution(* ActivemqController.testSync(...)")    //测试用，这里还额外指定了方法名称，方法参数类型，方法形参等，比较完整的切点表达式
//    public void myPointCut(){
//    }
    
 //   @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)" )
	
    @Around("execution("
    		+ "@org.springframework.web.bind.annotation.RequestMapping  "
    		+ "@org.springframework.web.bind.annotation.ResponseBody "
    		+ " * *(..))")
	public Object cahce(ProceedingJoinPoint  join ) throws Throwable{
    	
    	// 缓存文件
    	File  cacheFile = null; 
    	
    	// 返回参数
    	Object response = null;
    	
    	// 当前执行方法
    	Method method = null;
    	
    	// 获取方法参数
    	Object[]  args = join.getArgs();
    	
    	// 方法参数名
    	String[]  parameterNames = null;
    	
    	// 日志map
    	LinkedHashMap<String, Object>  logMap =  new LinkedHashMap<>();
    	
    	// 是否回滚事务
    	boolean isRollback = false;
    	
    	// 如果是方法
    	if (join.getSignature()  instanceof MethodSignature){
    		
    		// 获取方法签名
    		MethodSignature methodSignature = (MethodSignature)join.getSignature();
    		
    		// 获取方法名
    		parameterNames = methodSignature.getParameterNames();
    		
    		// 获取方法
    		method =  methodSignature.getMethod();
    		
    		// 获取方法类型
    		Class<?>[]  argsClass =  method.getParameterTypes();
    		
    		for (int i = 0 ; i < argsClass.length ; i ++){
    			
    			Class<?>  argClass = argsClass[i];
    			
    			// 如果类型是  Response  或者  是 Response 子类
    			if (argClass.getName().equals(Response.class.getName()) || Response.class.isAssignableFrom(argClass)){
    				
    				// 如果为空，实例化这个类
    				if (args[i] == null){
    					args[i] = argClass.newInstance();
    					
    					// 给response赋值  在出现错误的时候用
    					response = args[i];
    				}
    				
    			}
    			
    		   // 如果有日志map
               if (argClass.getName().equals(LinkedHashMap.class.getName())){
    				
    				// 如果为空，实例化这个类
    				if (args[i] == null){
    					args[i] = logMap;
    				}
    				
    			}
    			
    		}
    		
    		
    		// 如果该方法需要缓存
    		if (method.isAnnotationPresent(JsonCache.class)){
    			
    			JsonCache cahceAnnotation = method.getAnnotation(JsonCache.class);
    			
    			// 获取key字段名
    		    String keyFieldName = cahceAnnotation.keyFieldName();
    		    
    		    // 文件保存路径
    		    String filePath = cahceAnnotation.filePath();
    		    
    		    if (keyFieldName != null && keyFieldName.trim().length() != 0){
    		    	
    		    	// 去掉空格
    		    	keyFieldName = keyFieldName.trim();
    		    	
    		    	// 文件key
    		    	String fileKey = null;
    		    	
    		    	if (parameterNames != null && parameterNames.length > 0){
    		    		
    		    		for(int index = 0; index <= parameterNames.length ; index ++ ){
    		    			if(parameterNames[index].equals(keyFieldName)){
    		    				
    		    				if (args[index] != null){
        		    				fileKey = args[index].toString();
    		    				}
    		    				break;
    		    			}
    		    		}
    		    	}
    		    	
    		    	// 检查是否有文件名字
    		    	if (fileKey == null || fileKey.length() == 0){
    		    		throw new RuntimeException("keyFieldName is not Find or keyFieldName is null");
    		    	}
    		    	
    		    	// 检查是否有文件路径
    		    	if (filePath == null || filePath.length() == 0){
    		    		throw new RuntimeException(" filePath is empty");
    		    	}
    		    	
    		    	if (!filePath.endsWith("/")){
    		    		filePath = filePath + "/";
    		    	}
    		    	
    		    	if (!fileKey.toLowerCase().endsWith(".json")){
    		    		fileKey = fileKey + ".json";
    		    	}
    		    	
    		    	filePath = filePath + fileKey;
    		    	
    		    	// 创建缓存文件对象
    		    	cacheFile = new File(filePath);
    		    	
    		    }
    			
    		}
    		
    	}
    
    	
    	// 如果没有缓存文件，执行接口
    	if (cacheFile == null || !cacheFile.exists() || cacheFile.length() == 0){
    		
    		// 是否写入缓存
        	boolean isCache = true;
    		
    		// 错误信息
        	String errorMsg = null;
        	
    		try {
    			
    			// 执行用户方法
    			response = join.proceed(join.getArgs());
    			
    		} catch (Throwable e) {
    			e.printStackTrace();
    			errorMsg = ExceptionUtils.exceptionToString(e);
    		}
    		
    		// 如果有错误信息
    		if (errorMsg != null && response != null && response instanceof Response ){
    			
    			Response  resp = (Response)response;
    			resp.setSucc(false);
    			resp.setMsg(errorMsg);
    			
    			isCache = false;
    			
    		}
    		
    		// 写入缓存
    		if (cacheFile != null && isCache && response != null){
    			
    			String json = JSON.toJSONString(response);
    			FileUtils.writeStringToFile(cacheFile, json);
    		}
    		
    	}else{
    		// 读取缓存
    		if (method != null){
    			String json = FileUtils.readFileToString(cacheFile);
        		response = JSON.parseObject(json, method.getReturnType());
    		}
    	}
    	
    	// 判断是否需要回滚事务
    	if (isRollback){
    		
    		// 回滚当前线程事务
        	TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    	}
    	
    	// 写出日志
    	if (!logMap.isEmpty()){
    		 logMap.put("class",join.getTarget().getClass().getSimpleName() + "." + method.getName());
    	     System.out.println(JSON.toJSONString(logMap));
    	}
    	
    	return response;
    }

}
